import {
  CanActivate,
  ExecutionContext,
  HttpException,
  HttpStatus,
  Injectable,
  Logger,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import * as jsonwebtoken from 'jsonwebtoken';
import * as url from 'url';
import { jwt } from '../utils/jwt';
import { RedisUtilsService } from 'src/modules/redis-utils/redis-utils.service';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(private readonly redisUtilsService: RedisUtilsService) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    // 如果返回true则继续往下走，如果返回false就不会往下走，
    // 用于验证用户信息，校验token等
    // 校验token
    const request = context.switchToHttp().getRequest();
    // token可能是在请求头,请求头,url地址中,不管是在哪里传递过来的都接收处理
    const token =
      context.switchToRpc().getData().headers.token ||
      context.switchToHttp().getRequest().body.token ||
      this.getUrlQuery(request.url, 'token');
    Logger.log(`当前的token: ${token}`, 'AuthGuard');
    if (token) {
      // 第二种 单点登录
      const currentUserId = jwt.decodeToken(token);
      const redisData = await this.redisUtilsService.get(currentUserId);
      console.log('redis数据', JSON.stringify(redisData));
      if (Object.is(token, redisData.token)) {
        // 每次登录产生的token都不一致， 传入的token必须和 redis里面缓存的token一致
        request.user = redisData.user;
        return true;
      } else {
        throw new HttpException(
          'token已失效，请重新登录',
          HttpStatus.UNAUTHORIZED,
        );
      }

      // 第一种
      // try {
      //   const user = await this.verifyToken(token, process.env.SECRET);
      //   request.user = user;
      //   return true;
      // } catch (error) {
      //   Logger.error(error, 'auth');
      //   throw new HttpException(
      //     'Token无效，请重新登录',
      //     HttpStatus.UNAUTHORIZED,
      //   );
      // }
    } else {
      throw new HttpException('你没有登录，请先登录', HttpStatus.UNAUTHORIZED);
    }
  }

  private verifyToken(token: string, secret: string): Promise<any> {
    return new Promise((resolve, reject) => {
      jsonwebtoken.verify(token, secret, (err, payload) => {
        if (err) {
          console.log('--------error---start------------');
          console.log(err);
          console.log('--------error---end------------');
          reject(err);
        } else {
          resolve(payload);
        }
      });
    });
  }

  // 从url中获取query值
  getUrlQuery(urlPath: string, key?: string): string | { [k: string]: any } {
    const query = url.parse(urlPath, true).query;
    if (key) {
      return query[key];
    } else {
      return query;
    }
  }
}
/**
 * 不管注册顺序，守卫总是在中间件之后执行
 * 使用方式
 * 1、全局使用 app.useGlobalGuards(new AuthGuard())
 * 2、需要的模块中使用
 * 3、在接口中使用
 */
